package com.quick.develop.flowable.service.process.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quick.develop.flowable.constant.BpmConstants;
import com.quick.develop.framework.common.page.PageResult;
import com.quick.develop.framework.utils.StringUtils;
import com.quick.develop.framework.security.utils.SecurityUtils;
import com.quick.develop.flowable.domain.entrust.BpmEntrustDueReqVO;
import com.quick.develop.flowable.domain.entrust.BpmEntrustEx;
import com.quick.develop.flowable.domain.entrust.BpmEntrustExPageReqVO;
import com.quick.develop.flowable.domain.entrust.BpmEntrustInfoReqVO;
import com.quick.develop.flowable.mapper.BpmEntrustExMapper;
import com.quick.develop.flowable.service.process.IBpmEntrustExService;
import com.quick.develop.flowable.service.process.IBpmProcessInstanceService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.history.HistoricProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

import static com.quick.develop.flowable.enums.BpmErrorCodeConstants.PROCESS_ENTRUST_IS_EXISTS;
import static com.quick.develop.framework.common.utils.ServiceExceptionUtils.exception;
import static com.quick.develop.framework.utils.collection.CollectionUtils.*;

/**
 * @author junyuan.liu
 * @description:
 * @date 2022/9/4 14:41
 */
@Slf4j
@Service
public class BpmEntrustServiceExImpl extends ServiceImpl<BpmEntrustExMapper, BpmEntrustEx> implements IBpmEntrustExService {
    @Resource
    IBpmProcessInstanceService bpmProcessInstanceService;
    
    @Override
    public PageResult<BpmEntrustEx> selectPage(BpmEntrustExPageReqVO reqVO) {
        return baseMapper.selectPage(reqVO, SecurityUtils.getUserCode());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addEntrust(BpmEntrustEx entity) {
        if (isExist(entity)) {
            throw exception(PROCESS_ENTRUST_IS_EXISTS, entity.getModelKey());
        }
        return baseMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateEntrust(BpmEntrustEx entity) {
        if (isExist(entity)) {
            throw exception(PROCESS_ENTRUST_IS_EXISTS, entity.getModelKey());
        }
        return baseMapper.updateById(entity);
    }

    @Override
    public boolean isExist(BpmEntrustEx entity) {
        if (Objects.isNull(entity.getId())) {
            return baseMapper.selectCountByKey(entity.getModelKey(), SecurityUtils.getUserCode()) > 0;
        }else {
            BpmEntrustEx old = baseMapper.selectById(entity.getId());
            if (!Objects.equals(old.getModelKey(), entity.getModelKey())) {
                return baseMapper.selectCountByKey(entity.getModelKey(),SecurityUtils.getUserCode()) > 0;
            }
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteEntrust(Long[] ids) {
        return baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    public List<BpmEntrustEx> getEntrustList(BpmEntrustInfoReqVO reqVO) {
        return baseMapper.selectList(reqVO);
    }

    @Override
    public Map<String, String> getEntrustUserMap(BpmEntrustInfoReqVO reqVO) {
        List<BpmEntrustEx> list = getEntrustList(reqVO);

        return convertMap(list, BpmEntrustEx::getCreatedUserCode, BpmEntrustEx::getEntrustToUser);
    }

    @Override
    public Set<String> getEntrustUserSet(BpmEntrustInfoReqVO reqVO) {
        if (reqVO.getCreatedUsers().isEmpty()) {
            return Collections.emptySet();
        }
        Map<String, String> map = getEntrustUserMap(reqVO);
        Set<String> users = reqVO.getCreatedUsers();
        return Optional.ofNullable(map)
                .map(m -> convertSet(users, u -> Optional.ofNullable(map.get(u)).orElse(u)))
                .orElse(users);
    }

    @Override
    public List<String> getEntrustUserList(BpmEntrustInfoReqVO reqVO) {
        if (reqVO.getCreatedUsers().isEmpty()) {
            return Collections.emptyList();
        }
        Map<String, String> map = getEntrustUserMap(reqVO);
        Set<String> users = reqVO.getCreatedUsers();
        return Optional.ofNullable(map)
                .map(m -> convertList(users, u -> Optional.ofNullable(map.get(u)).orElse(u)))
                .orElse(new ArrayList<>(users));
    }

    @Override
    public String getEntrustUser(BpmEntrustInfoReqVO reqVO) {
        if (StringUtils.isEmpty(reqVO.getCreatedUser())) {
            return null;
        }
        String user = null;
        // 查询当前流程
        List<BpmEntrustEx> list = this.getEntrustList(reqVO);
        user = CollUtil.isEmpty(list) ? null : list.get(0).getEntrustToUser();
        
        if (StringUtils.isEmpty(user)) {
            //查询是否有主流程
            HistoricProcessInstance instance = bpmProcessInstanceService.getMainProcessInstanceByProcessInstanceId(reqVO.getProcessInstanceId());
            // 存在主流程
            if (Objects.nonNull(instance) && !Objects.equals(instance.getProcessDefinitionKey(), reqVO.getModelKey())) {
                reqVO.setModelKey(instance.getProcessDefinitionKey());
                List<BpmEntrustEx> list1 = this.getEntrustList(reqVO);
                user = CollUtil.isEmpty(list1) ? null : list1.get(0).getEntrustToUser();
            }
            if (StringUtils.isEmpty(user)) {
                // 查询是否存在一键委托
                reqVO.setModelKey(BpmConstants.ALL_PROCESS);
                List<BpmEntrustEx> list1 = this.getEntrustList(reqVO);
                user = CollUtil.isEmpty(list1) ? null : list1.get(0).getEntrustToUser();
            }
        }
        
        return user;
    }

    @Override
    public BpmEntrustEx getOverdueEntrust(BpmEntrustDueReqVO reqVO) {
        if (StringUtils.isEmpty(reqVO.getEntrustUser()) || StringUtils.isEmpty(reqVO.getModelKey())) {
            return null;
        }
        List<BpmEntrustEx> list = baseMapper.selectOverdueEntrust(reqVO);
        if (CollUtil.isEmpty(list)) {
            //查询是否有主流程
            HistoricProcessInstance instance = bpmProcessInstanceService.getMainProcessInstanceByProcessInstanceId(reqVO.getProcessInstanceId());
            // 存在主流程
            if (Objects.nonNull(instance) && !Objects.equals(instance.getProcessDefinitionKey(), reqVO.getModelKey())) {
                reqVO.setModelKey(instance.getProcessDefinitionKey());
                list = baseMapper.selectOverdueEntrust(reqVO);
                return CollUtil.isEmpty(list) ? null : list.get(0);
            }
            // 查询是否存在一键委托
            reqVO.setModelKey(BpmConstants.ALL_PROCESS);
            list = baseMapper.selectOverdueEntrust(reqVO);
            return CollUtil.isEmpty(list) ? null : list.get(0);
        }
        return CollUtil.isEmpty(list) ? null : list.get(0);
    }

    @Override
    public List<BpmEntrustEx> getOverdueEntrustList(BpmEntrustDueReqVO reqVO) {
        if (reqVO.getEntrustUsers().isEmpty() || reqVO.getModelKeys().isEmpty()) {
            return Collections.emptyList();
        }
        return baseMapper.selectOverdueEntrust(reqVO);
    }
}
